package com.inspection.service.impl;

import com.google.common.collect.Lists;
import com.inspection.constant.YesNoEnum;
import com.inspection.dao.InspectionBasicDao;
import com.inspection.dao.InspectionDepartmentDao;
import com.inspection.dao.InspectionDeptRegulationDao;
import com.inspection.dao.InspectionRegulationDao;
import com.inspection.entity.InspectionBasicDO;
import com.inspection.entity.InspectionDepartmentDO;
import com.inspection.entity.InspectionDeptRegulationDO;
import com.inspection.entity.InspectionRegulationDO;
import com.inspection.model.dto.InspectionRegulationDTO;
import com.inspection.model.dto.InspectionRegulationQueryDTO;
import com.inspection.service.InspectionRegulationService;
import com.inspection.support.AssertUtils;
import com.inspection.support.PageHelper;
import com.inspection.support.model.BusinessBaseException;
import com.inspection.support.model.DataTree;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class  InspectionRegulationServiceImpl implements InspectionRegulationService{

    static Sort sort = new Sort(Sort.Direction.DESC,"id");

    @Autowired
    private InspectionRegulationDao inspectionRegulationDao;

    @Autowired
    private InspectionDeptRegulationDao inspectionDeptRegulationDao;




    @Override
    public List<InspectionRegulationDO> queryRegulation(InspectionRegulationQueryDTO query) {
        if(Objects.nonNull(query.getDepartmentId())){
            //部门关联的条例一定是 叶子结点 可执行的条例
            InspectionDeptRegulationDO deptRegulation=new InspectionDeptRegulationDO();
            deptRegulation.setDeptId(query.getDepartmentId());
            List<InspectionDeptRegulationDO> allRegulations = inspectionDeptRegulationDao.findAll(Example.of(deptRegulation));
            List<Long> regulationIds = allRegulations.stream().map(m -> m.getRegulationId()).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(regulationIds)){


              return    inspectionRegulationDao.findAll((Specification<InspectionRegulationDO>) (root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> predicates = Lists.newArrayList();

                    Predicate finalConditions = criteriaBuilder.conjunction();
                    CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("id"));
                    for (Long rId : regulationIds) {
                        in.value(rId);
                    }
                    finalConditions = criteriaBuilder.and(finalConditions, in);
                    predicates.add(finalConditions);

                    Predicate isDel = criteriaBuilder.equal(root.get("isDel"), 0);
                    predicates.add(isDel);

                    return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
                });

            }else{
                return new ArrayList<>();
            }
        }
        InspectionRegulationDO regulationQuery= new InspectionRegulationDO();
        regulationQuery.setIsDel(0);

        return inspectionRegulationDao.findAll(Example.of(regulationQuery),sort);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRegulation(InspectionRegulationDTO save) {
        this.checkParam(save);
        InspectionRegulationDO saveDO = new InspectionRegulationDO();

        BeanUtils.copyProperties(save,saveDO);
        saveDO.setId(null);
        saveDO.setDateCreate(new Date());
        saveDO.setIsDel(0);
        inspectionRegulationDao.saveAndFlush(saveDO);


        //如果插入的是 非叶子结点 也就是目录条例 无需插入中间表
        if(YesNoEnum.YES.getVal()!=save.getIsLeafNode()){
            return;
        }
        if(CollectionUtils.isEmpty(save.getExecuteDepts())){
            return;
        }
        List<Long> executeDepartments = save.getExecuteDepts();
        for (Long executeDepartment : executeDepartments) {
            InspectionDeptRegulationDO deptRegulationDO = new InspectionDeptRegulationDO();
            deptRegulationDO.setDeptId(executeDepartment);
            deptRegulationDO.setRegulationId(saveDO.getId());
            deptRegulationDO.setDateCreate(new Date());
            inspectionDeptRegulationDao.saveAndFlush(deptRegulationDO);
        }
    }

    private void checkParam(InspectionRegulationDTO save) {
        String regux = "([0-9]|[\\-+#])+?";
        if (!Pattern.matches(regux, save.getRegulationNo())) {
            throw new BusinessBaseException("考核编号必须是***-***-***格式");
        }
    }

    @Override
    public Page<InspectionRegulationDO> pageRegulation(InspectionRegulationQueryDTO page) {
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        InspectionRegulationDO regulationQuery= new InspectionRegulationDO();
        regulationQuery.setIsDel(0);
        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), sort);
        return inspectionRegulationDao.findAll(Example.of(regulationQuery),pageable);
    }

    @Override
    public DataTree getRegulationTree(InspectionRegulationQueryDTO query) {
        List<InspectionRegulationDO> regulations = queryRegulation(query);

        //先构建根结点
        DataTree.TreeNode rootNode=new DataTree.TreeNode();

        InspectionRegulationDO rootRegu = new InspectionRegulationDO();
        rootRegu.setId(-1L);
        rootRegu.setRegulationName("根结点");
        BeanUtils.copyProperties(rootRegu,rootNode);

        //根据根结点循环获取下面的结点
        Map<Long, List<InspectionRegulationDO>> parentMap = regulations.stream().collect(Collectors.groupingBy(InspectionRegulationDO::getParentId));

        findDeep(rootNode,parentMap);


        DataTree dataTree = new DataTree();
        dataTree.setRootNode(rootNode);
        dataTree.setTreeName("树名字");
        return dataTree;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRegulation(InspectionRegulationDTO update) {

        AssertUtils.nonNull(update.getId(),"考核id不能為空！");
        InspectionRegulationDO regulation = inspectionRegulationDao.getOne(update.getId());
        if(Objects.isNull(regulation)){
            throw new BusinessBaseException("考核条例不存在！");
        }
        regulation.setLowestScore(update.getLowestScore());
        regulation.setHighestScore(update.getHighestScore());
        regulation.setRegulationName(update.getRegulationName());
        regulation.setRegulationContent(update.getRegulationContent());
        regulation.setRemark(update.getRemark());
        inspectionRegulationDao.saveAndFlush(regulation);
        //如果存在可执行部门的编辑操作

        inspectionDeptRegulationDao.deleteByRegulationId(regulation.getId());


        if(CollectionUtils.isEmpty(update.getExecuteDepts())){
            return;
        }
        List<Long> executeDepartments = update.getExecuteDepts();
        for (Long executeDepartment : executeDepartments) {
            InspectionDeptRegulationDO newDeptRegulation = new InspectionDeptRegulationDO();
            newDeptRegulation.setDeptId(executeDepartment);
            newDeptRegulation.setRegulationId(update.getId());
            newDeptRegulation.setDateCreate(new Date());
            inspectionDeptRegulationDao.saveAndFlush(newDeptRegulation);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delRegulation(InspectionRegulationDTO del) {
        AssertUtils.nonNull(del.getId(),"考核id不能為空！");
        InspectionRegulationDO regulation = inspectionRegulationDao.getOne(del.getId());
        if(Objects.isNull(regulation)){
            throw new BusinessBaseException("考核条例不存在！");
        }
        regulation.setIsDel(1);
        inspectionRegulationDao.saveAndFlush(regulation);

        //直接硬删除 关联数据
        inspectionDeptRegulationDao.deleteByRegulationId(regulation.getId());


    }

    @Override
    public InspectionRegulationDO getRegulation(InspectionRegulationDTO query) {
        AssertUtils.nonNull(query.getId(),"考核id不能為空！");
        Optional<InspectionRegulationDO> regulationOp = inspectionRegulationDao.findById(query.getId());
        if(!regulationOp.isPresent()){
            throw new BusinessBaseException("考核条例不存在！");
        }
        InspectionRegulationDO regulation = regulationOp.get();
        //查询 可执行的部门信息
        InspectionDeptRegulationDO deptRegulationParam = new InspectionDeptRegulationDO();
        deptRegulationParam.setRegulationId(query.getId());
        List<InspectionDeptRegulationDO> deptRegulationDOS = inspectionDeptRegulationDao.findAll(Example.of(deptRegulationParam));
        if(CollectionUtils.isEmpty(deptRegulationDOS)){
            return regulation;
        }
        List<Long> deptIds = deptRegulationDOS.stream().map(d -> d.getDeptId()).collect(Collectors.toList());
        regulation.setExecuteDepts(deptIds);
//        List<InspectionDepartmentDO> executeDepts = inspectionDepartmentDao.findAllById(deptIds);
//        regulation.setExecuteDepts(executeDepts);
        return regulation;
    }


    public void findDeep(DataTree.TreeNode node,Map<Long, List<InspectionRegulationDO>> parentMap){
        List<InspectionRegulationDO> regulationDOS = parentMap.get(node.getId());
        if (CollectionUtils.isEmpty(regulationDOS)) {
            return;
        }
        List<DataTree.TreeNode> dos = new ArrayList<>(regulationDOS.size());

        for (InspectionRegulationDO regulationDO : regulationDOS) {
            DataTree.TreeNode treeNode = new DataTree.TreeNode();
            BeanUtils.copyProperties(regulationDO,treeNode);
            dos.add(treeNode);
            findDeep(treeNode, parentMap);
        }
        Collections.sort(dos, (o1, o2) -> {
            if(o1.getRegulationNo()==null||o2.getRegulationNo()==null){
                return 0;
            }

            int lastIndex1 = o1.getRegulationNo().lastIndexOf("-");
            String o1Value;
            if(lastIndex1==-1){
                o1Value=o1.getRegulationNo();
            }else{
                o1Value= o1.getRegulationNo().substring(lastIndex1+1);
            }

            int lastIndex2 = o2.getRegulationNo().lastIndexOf("-");
            String o2Value;
            if(lastIndex2==-1){
                o2Value=o2.getRegulationNo();
            }else{
                o2Value= o2.getRegulationNo().substring(lastIndex2+1);
            }

            return Integer.valueOf(o1Value).compareTo(Integer.valueOf(o2Value));
        });
        node.setChildren(dos);
    }
}
